package com.qf.openapi.zuul.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import com.qf.openapi.zuul.feign.CacheFeignClient;
import com.qf.openapi.zuul.utils.ZuulLocalCache;
import com.qf.qfsy.constants.CacheConstants;
import com.qf.qfsy.vo.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;

@Component
@Slf4j
public class DynamicRoutingFilter extends ZuulFilter {

    @Autowired
    CacheFeignClient cacheFeignClient;

    @Override
    public String filterType() {
        // 前置过滤器
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        // 把这个过滤器放到所有自定义过滤器的最后
        return 100;
    }

    @Override
    public boolean shouldFilter() {

        // 尊重前面过滤器的判断结果
        RequestContext currentContext = RequestContext.getCurrentContext();
        boolean b = currentContext.sendZuulResponse();

        return b;
    }

    @Override
    public Object run() throws ZuulException {

        //1. 获取请求中的参数 apiname 的值
        RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletRequest request = currentContext.getRequest();
        String apiname = request.getParameter("apiname");

        //2. 根据apiname的值，查询redis中对应的路由信息
        HashMap<String,Object> routingInfo = getRoutingInfo(apiname);

        //3. 执行动态路由
        if (routingInfo!=null&&routingInfo.size()>0){

            String serviceId = (String) routingInfo.get("serviceId");
            String serviceUrl = (String) routingInfo.get("insideApiUrl");
            log.info("{}请求被发送到微服务{}的{}接口了",apiname,serviceId,serviceUrl);
            // 设置把当前请求发送给哪个微服务，serviceId是nacos中微服务的名字
            currentContext.put(FilterConstants.SERVICE_ID_KEY,serviceId);
            // 设置微服务的接口路径
            currentContext.put(FilterConstants.REQUEST_URI_KEY,serviceUrl);
            return null;
        }else {
            log.info("{}请求没有找到对应的微服务",apiname);
            // 让请求就此打住，不要给后面的微服务发送了
            currentContext.setSendZuulResponse(false);
            // 没有找到路由信息，给出错误提示
            HttpServletResponse response = currentContext.getResponse();
            response.setContentType("text/html;charset=utf-8");
            try {
                response.getWriter().println("服务不存在，请检查服务名参数apiname是否正确!");
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            return null;
        }

    }

    /**
     * 根据接口名，查询对应的路由信息
     * @param apiname
     * @return
     */
    private HashMap<String, Object> getRoutingInfo(String apiname) {

        // 安装规则拼装 key
        String key = CacheConstants.OPENAPI_MAPPING_PREFIX+apiname;

        // 首先查询本地缓存
        HashMap cache = (HashMap) ZuulLocalCache.routingCache.get(key);
        if (cache!=null&&cache.size()>0){
            log.info("本地缓存命中了，路由信息为{}",cache);
            return cache;
        }

        // 本地缓存没有命中，则查缓存模块
        R result = cacheFeignClient.hmget(key);
        HashMap routingInfo = (HashMap) result.getData();
        // 查到的路由信息放入本地缓存中
        log.info("把路由信息放入本地缓存中，key={},路由信息为{}",key,routingInfo);
        ZuulLocalCache.routingCache.put(key,routingInfo);

        return routingInfo;


//        HashMap<String, Object> hashMap = new HashMap<>();
//
//        hashMap.put("serviceId","openapi-wxpay");
//
//        // 注意，zuul网关转发请求时，这个url需要以 / 开头
//        // 否则微服务接受不到这个路径
//        hashMap.put("insideApiUrl","/getpayurl");
//
//        return hashMap;
    }
}
